using System.Collections;
using HybridCLR;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Networking;
using YooAsset;

public partial class Boot : MonoBehaviour
{
#if ODIN_INSPECTOR
    [Sirenix.OdinInspector.Title("HybridCLR Settings",TitleAlignment = Sirenix.OdinInspector.TitleAlignments.Centered)]
#else
    [Header("HybridCLR Settings")]
#endif
    [Tooltip("hybrid的meta注入模式")]
    public HomologousImageMode HybridMode;
    [Tooltip("热更新的dll可以，带不带.dll后缀都可以")]
    public List<string> hotFixAssemblys;
    [Tooltip("局域网运行的时候，便于开发的时候，使用局域网服务器下载修改编译的dll")]
    public bool hybridWebRequest = false;
    /// <summary>
    /// 为aot assembly加载原始metadata， 这个代码放aot或者热更新都行。
    /// 一旦加载后，如果AOT泛型函数对应native实现不存在，则自动替换为解释模式执行
    /// </summary>
    /// <param name="yooPlayMode"></param>
    public IEnumerator LoadMetadataForAOTAssemblies()
    {
        var AOTMetaAssemblyNames = AOTGenericReferences.PatchedAOTAssemblyList.ToList();
        /// 注意，补充元数据是给AOT dll补充元数据，而不是给热更新dll补充元数据。
        /// 热更新dll不缺元数据，不需要补充，如果调用LoadMetadataForAOTAssembly会返回错误
        foreach (var aotDllName in AOTMetaAssemblyNames)
        {
            if(hybridWebRequest)
            {
                var dllFile =aotDllName + (aotDllName.EndsWith(".dll")?"":".dll");
                var request = UnityWebRequest.Get($"{hostServerIP}/UnityPlayer/{appVersion}/AssembliesPostIl2CppStrip/{dllFile}");
                yield return request.SendWebRequest();
                if(request.result == UnityWebRequest.Result.Success)
                {
                    var dllBytes = request.downloadHandler.data;
                    // 加载assembly对应的dll，会自动为它hook。一旦aot泛型函数的native函数不存在，用解释器版本代码
                    LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, HybridMode);
                    Debug.Log($"LoadMetadataForAOTAssembly : {dllFile}. mode:{HybridMode} ret:{err}");
                }
            }
            else
            {
                var dllBytesFile ="Assets/DLC/HybridCLR/Metas/"+ aotDllName.Replace(".dll", ".bytes");
                if (string.IsNullOrEmpty(YooAssets.GetAssetInfo(dllBytesFile).Error))
                {
                    var handle = YooAssets.LoadAssetSync<TextAsset>(dllBytesFile);
                    yield return handle;
                    var dllBytes = handle.GetAssetObject<TextAsset>().bytes;
                    // 加载assembly对应的dll，会自动为它hook。一旦aot泛型函数的native函数不存在，用解释器版本代码
                    LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, HybridMode);
                    Debug.Log($"LoadMetadataForAOTAssembly : {dllBytesFile}. mode:{HybridMode} ret:{err}");
                }
            }
        }
        Debug.Log($"LoadMetadataForAOTAssembly Done !!!");
    }

    /// <summary>
    /// 加载热更dll
    /// </summary>
    /// <param name="AssemblyNames">热更dll集合</param>
    /// <returns></returns>
    public IEnumerator LoadHotfixAssemblies()
    {
        if (hotFixAssemblys != null)
        {
            foreach (var aotDllName in hotFixAssemblys)
            {
                if(hybridWebRequest)
                {
                    var dllFile =aotDllName + (aotDllName.EndsWith(".dll")?"":".dll");
                    var request = UnityWebRequest.Get($"{hostServerIP}/UnityPlayer/{appVersion}/HotUpdateDlls/{dllFile}");
                    yield return request.SendWebRequest();
                    if(request.result == UnityWebRequest.Result.Success)
                    {
                        var dllBytes = request.downloadHandler.data;
                        var assembly = System.Reflection.Assembly.Load(dllBytes);
                        Debug.Log($"LoadAssembly :"+assembly);
                    }
                }
                else
                {
                    var dllBytesFile = "Assets/DLC/HybridCLR/HotFix/"+ aotDllName.Replace(".dll", ".bytes");
                    if (string.IsNullOrEmpty(YooAssets.GetAssetInfo(dllBytesFile).Error))
                    {
                        var handle = YooAssets.LoadAssetSync<TextAsset>(dllBytesFile);
                        yield return handle;
                        var dllBytes = handle.GetAssetObject<TextAsset>().bytes;
                        var assembly = System.Reflection.Assembly.Load(dllBytes);
                        Debug.Log($"LoadAssembly :"+assembly);
                    }
                }
            }
        }
        Debug.Log($"Load Assembly Done !!!");
    } 
}
